package com.dream21th.dream21thredis.config;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.MapPropertySource;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * redis工厂
 * @author dream21th
 *
 */
@Service
public class RedisPoolFactory extends CachingConfigurerSupport{

	@Autowired
	RedisConfig redisConfig;
	
	/**
	 * redis单例模式
	 * @return
	 */
	@Bean
	public JedisPool JedisPoolFactory() {
		JedisPoolConfig poolConfig = new JedisPoolConfig();
		poolConfig.setMaxIdle(redisConfig.getPoolMaxIdle());
		poolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
		poolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait() * 1000);
		JedisPool jp = new JedisPool(poolConfig, redisConfig.getHost(), redisConfig.getPort(),
				redisConfig.getTimeout()*1000, redisConfig.getPassword(), 0);
		return jp;
	}
	
	/**
	 * redis集群模式
	 * @return
	 */
	@Bean
	public JedisCluster getJedisCluster() {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(redisConfig.getCluster().getMaxTotal());
        config.setMaxIdle(redisConfig.getCluster().getMaxIdle());
        config.setMaxWaitMillis(redisConfig.getCluster().getMaxWaitMills());
        config.setTestOnBorrow(redisConfig.getCluster().getTestOnBorrow());
        List<String> node=Arrays.asList(redisConfig.getCluster().getNodes().split(","));
        // 集群模式
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        Set<HostAndPort> nodes = new HashSet<HostAndPort>();
        node.forEach(n->{
        	String[] ip=n.split(":");
        	HostAndPort hostAndPort = new HostAndPort(ip[0],Integer.parseInt(ip[1]));
        	nodes.add(hostAndPort);
        });
        JedisCluster jedisCluster = new JedisCluster(nodes, poolConfig);
        return jedisCluster;
    }
	

	/**
	 * 提供集群部署的情况下面的redisTemplate支持
	 * @param factory
	 * @return
	 */
	@Bean("redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
        redisTemplate.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(om);
        redisTemplate.setKeySerializer(serializer);
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.afterPropertiesSet();
        //redisTemplate.setEnableTransactionSupport(true);
        return redisTemplate;
    }
	
	 /**
     * jedis 连接池
     * @return
     */
    private JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(redisConfig.getCluster().getMaxTotal());
        config.setMaxIdle(redisConfig.getCluster().getMaxIdle());
        config.setMaxWaitMillis(redisConfig.getCluster().getMaxWaitMills());
        config.setTestOnBorrow(redisConfig.getCluster().getTestOnBorrow());
        return config;
    }
    
    @Bean(name = "redisCacheManager")
    public CacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        cacheManager.setDefaultExpiration(1800);
        return cacheManager;
    }
    
    /**
     * redisCluster配置
     *
     * @return
     */
    @Bean
    public RedisClusterConfiguration redisProperties() {
        Map<String, Object> source = new HashMap<String, Object>();
        source.put("spring.redis.cluster.nodes", redisConfig.getCluster().getNodes());
        source.put("spring.redis.cluster.timeout", redisConfig.getCluster().getConnectionTimeOut());
        return new RedisClusterConfiguration(new MapPropertySource("RedisProperties", source));
    }
    
    @Bean("jedisConnFactory")
    public JedisConnectionFactory jedisConnectionFactory() {
        //redis cluster
        JedisConnectionFactory factory = new JedisConnectionFactory(redisProperties(),jedisPoolConfig());
        return factory;
    }
}
